!< PENF string-to-number (and viceversa) facility.

module penf_stringify
!< PENF string-to-number (and viceversa) facility.
use, intrinsic :: iso_fortran_env, only : stderr=>error_unit
use penf_b_size
use penf_global_parameters_variables

implicit none
private
save
public :: str_ascii, str_ucs4
public :: str, strz, cton
public :: bstr, bcton

interface str_ascii
   !< Convert string of any kind to ASCII string.
   module procedure str_ascii_default
#if defined _ASCII_SUPPORTED && defined _ASCII_NEQ_DEFAULT
   module procedure str_ascii_ascii
#endif
#ifdef _UCS4_SUPPORTED
   module procedure str_ascii_ucs4
#endif
endinterface

interface str_ucs4
   !< Convert string of any kind to UCS4 string.
   module procedure str_ucs4_default
#if defined _ASCII_SUPPORTED && defined _ASCII_NEQ_DEFAULT
   module procedure str_ucs4_ascii
#endif
#ifdef _UCS4_SUPPORTED
   module procedure str_ucs4_ucs4
#endif
endinterface

interface str
  !< Convert number (real and integer) to string (number to string type casting).
  module procedure                       &
#if defined _R16P
                   strf_R16P,str_R16P,   &
#endif
                   strf_R8P ,str_R8P,    &
                   strf_R4P ,str_R4P,    &
                   strf_I8P ,str_I8P,    &
                   strf_I4P ,str_I4P,    &
                   strf_I2P ,str_I2P,    &
                   strf_I1P ,str_I1P,    &
                             str_bol,    &
#if defined _R16P
                             str_a_R16P, &
#endif
                             str_a_R8P,  &
                             str_a_R4P,  &
                             str_a_I8P,  &
                             str_a_I4P,  &
                             str_a_I2P,  &
                             str_a_I1P
endinterface

interface strz
  !< Convert integer, to string, prefixing with the right number of zeros (integer to string type casting with zero padding).
  module procedure strz_I8P, strz_I4P, strz_I2P, strz_I1P
endinterface

interface cton
  !< Convert string to number (real and integer, string to number type casting).
  module procedure            &
#if defined _R16P
                   ctor_R16P, &
#endif
                   ctor_R8P,  &
                   ctor_R4P,  &
                   ctoi_I8P,  &
                   ctoi_I4P,  &
                   ctoi_I2P,  &
                   ctoi_I1P
endinterface

interface bstr
  !< Convert number (real and integer) to bit-string (number to bit-string type casting).
  module procedure            &
#if defined _R16P
                   bstr_R16P, &
#endif
                   bstr_R8P,  &
                   bstr_R4P,  &
                   bstr_I8P,  &
                   bstr_I4P,  &
                   bstr_I2P,  &
                   bstr_I1P
endinterface

interface bcton
  !< Convert bit-string to number (real and integer, bit-string to number type casting).
  module procedure             &
#if defined _R16P
                   bctor_R16P, &
#endif
                   bctor_R8P,  &
                   bctor_R4P,  &
                   bctoi_I8P,  &
                   bctoi_I4P,  &
                   bctoi_I2P,  &
                   bctoi_I1P
endinterface

contains
   pure function str_ascii_default(input) result(output)
   !< Convert string of default kind to ASCII string.
   !<
   !<```fortran
   !< use penf
   !< character(len=:, kind=ASCII), allocatable :: string
   !< string = str_ascii('I was DEFAULT kind, but now I am ASCII')
   !< print "(A)", string
   !<```
   !=> I was DEFAULT kind, but now I am ASCII <<<
   character(len=*), intent(in)              :: input  !< Input string of default kind.
   character(len=:, kind=ASCII), allocatable :: output !< Output string of ASCII kind.

   output = input
   endfunction str_ascii_default

   pure function str_ascii_ascii(input) result(output)
   !< Convert string of ASCII kind to ASCII string, just for convenience in sanitize strings.
   !<
   !<```fortran
   !< use penf
   !< character(len=:, kind=ASCII), allocatable :: string
   !< string = str_ascii('I was ASCII kind and I am still ASCII')
   !< print "(A)", string
   !<```
   !=> I was ASCII kind and I am still ASCII <<<
   character(len=*, kind=ASCII), intent(in)  :: input  !< Input string of ASCII kind.
   character(len=:, kind=ASCII), allocatable :: output !< Output string of ASCII kind.

   output = input
   endfunction str_ascii_ascii

   pure function str_ascii_ucs4(input) result(output)
   !< Convert string of UCS4 kind to ASCII string.
   !<
   !<```fortran
   !< use penf
   !< character(len=:, kind=ASCII), allocatable :: string
   !< string = str_ascii(UCS4_'I was UCS4 kind, but now I am ASCII')
   !< print "(A)", string
   !<```
   !=> I was UCS4 kind, but now I am ASCII <<<
   character(len=*, kind=UCS4), intent(in)   :: input  !< Input string of UCS4 kind.
   character(len=:, kind=ASCII), allocatable :: output !< Output string of ASCII kind.

   output = input
   endfunction str_ascii_ucs4

   pure function str_ucs4_default(input) result(output)
   !< Convert string of default kind to UCS4 string.
   !<
   !<```fortran
   !< use penf
   !< character(len=:, kind=UCS4), allocatable :: string
   !< string = str_ascii('I was DEFAULT kind, but now I am UCS4')
   !< print "(A)", string
   !<```
   !=> I was DEFAULT kind, but now I am UCS4 <<<
   character(len=*), intent(in)             :: input  !< Input string of default kind.
   character(len=:, kind=UCS4), allocatable :: output !< Output string of UCS4 kind.

   output = input
   endfunction str_ucs4_default

   pure function str_ucs4_ascii(input) result(output)
   !< Convert string of ASCII kind to UCS4 string.
   !<
   !<```fortran
   !< use penf
   !< character(len=:, kind=UCS4), allocatable :: string
   !< string = str_ascii(ASCII_'I was ASCII kind, but now I am UCS4')
   !< print "(A)", string
   !<```
   !=> I was ASCII kind, but now I am UCS4 <<<
   character(len=*, kind=ASCII), intent(in) :: input  !< Input string of ASCII kind.
   character(len=:, kind=UCS4), allocatable :: output !< Output string of UCS4 kind.

   output = input
   endfunction str_ucs4_ascii

   pure function str_ucs4_ucs4(input) result(output)
   !< Convert string of UCS4 kind to UCS4 string, just for convenience in sanitize strings.
   !<
   !<```fortran
   !< use penf
   !< character(len=:, kind=UCS4), allocatable :: string
   !< string = str_ascii(UCS4_'I was UCS4 kind and I am still UCS4')
   !< print "(A)", string
   !<```
   !=> I was UCS4 kind and I am still UCS4 <<<
   character(len=*, kind=UCS4), intent(in)  :: input  !< Input string of UCS4 kind.
   character(len=:, kind=UCS4), allocatable :: output !< Output string of UCS4 kind.

   output = input
   endfunction str_ucs4_ucs4

   elemental function strf_R16P(fm, n) result(str)
   !< Convert real to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FR16P, n=1._R16P)
   !<```
   !=> 0.100000000000000000000000000000000E+0001 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   real(R16P),   intent(in) :: n   !< Real to be converted.
   character(DR16P)         :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_R16P

   elemental function strf_R8P(fm, n) result(str)
   !< Convert real to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FR8P, n=1._R8P)
   !<```
   !=> 0.100000000000000E+001 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   real(R8P),    intent(in) :: n   !< Real to be converted.
   character(DR8P)          :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_R8P

   elemental function strf_R4P(fm, n) result(str)
   !< Convert real to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FR4P, n=1._R4P)
   !<```
   !=> 0.100000E+01 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   real(R4P),    intent(in) :: n   !< Real to be converted.
   character(DR4P)          :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_R4P

   elemental function strf_I8P(fm, n) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FI8P, n=1_I8P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   integer(I8P), intent(in) :: n   !< Integer to be converted.
   character(DI8P)          :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_I8P

   elemental function strf_I4P(fm, n) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FI4P, n=1_I4P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   integer(I4P), intent(in) :: n   !< Integer to be converted.
   character(DI4P)          :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_I4P

   elemental function strf_I2P(fm, n) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FI2P, n=1_I2P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   integer(I2P), intent(in) :: n   !< Integer to be converted.
   character(DI2P)          :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_I2P

   elemental function strf_I1P(fm, n) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(fm=FI1P, n=1_I1P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: fm  !< Format different from the standard for the kind.
   integer(I1P), intent(in) :: n   !< Integer to be converted.
   character(DI1P)          :: str !< Returned string containing input number.

   write(str, trim(fm)) n
   endfunction strf_I1P

   elemental function str_R16P(n, no_sign, compact) result(str)
   !< Convert real to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R16P)
   !<```
   !=> -0.100000000000000000000000000000000E+0001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R16P, no_sign=.true.)
   !<```
   !=> 0.100000000000000000000000000000000E+0001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R16P, compact=.true.)
   !<```
   !=> -0.1E+1 <<<
   real(R16P), intent(in)           :: n       !< Real to be converted.
   logical,    intent(in), optional :: no_sign !< Flag for leaving out the sign.
   logical,    intent(in), optional :: compact !< Flag for *compacting* string encoding.
   character(DR16P)                 :: str     !< Returned string containing input number.

   write(str, FR16P) n               ! Casting of n to string.
   if (n>0._R16P) str(1:1)='+'       ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   if (present(compact)) then
     if (compact) call compact_real_string(string=str)
   endif
   endfunction str_R16P

   elemental function str_R8P(n, no_sign, compact) result(str)
   !< Convert real to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R8P)
   !<```
   !=> -0.100000000000000E+001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R8P, no_sign=.true.)
   !<```
   !=> 0.100000000000000E+001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R8P, compact=.true.)
   !<```
   !=> -0.1E+1 <<<
   real(R8P), intent(in)           :: n       !< Real to be converted.
   logical,   intent(in), optional :: no_sign !< Flag for leaving out the sign.
   logical,   intent(in), optional :: compact !< Flag for *compacting* string encoding.
   character(DR8P)                 :: str     !< Returned string containing input number.

   write(str, FR8P) n                ! Casting of n to string.
   if (n>0._R8P) str(1:1)='+'        ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   if (present(compact)) then
     if (compact) call compact_real_string(string=str)
   endif
   endfunction str_R8P

   elemental function str_R4P(n, no_sign, compact) result(str)
   !< Convert real to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R4P)
   !<```
   !=> -0.100000E+01 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R4P, no_sign=.true.)
   !<```
   !=> 0.100000E+01 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1._R4P, compact=.true.)
   !<```
   !=> -0.1E+1 <<<
   real(R4P), intent(in)           :: n       !< Real to be converted.
   logical,   intent(in), optional :: no_sign !< Flag for leaving out the sign.
   logical,   intent(in), optional :: compact !< Flag for *compacting* string encoding.
   character(DR4P)                 :: str     !< Returned string containing input number.

   write(str, FR4P) n                ! Casting of n to string.
   if (n>0._R4P) str(1:1)='+'        ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   if (present(compact)) then
     if (compact) call compact_real_string(string=str)
   endif
   endfunction str_R4P

   elemental function str_I8P(n, no_sign) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I8P)
   !<```
   !=> -1 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I8P, no_sign=.true.)
   !<```
   !=> 1 <<<
   integer(I8P), intent(in)           :: n       !< Integer to be converted.
   logical,      intent(in), optional :: no_sign !< Flag for leaving out the sign.
   character(DI8P)                    :: str     !< Returned string containing input number plus padding zeros.

   write(str, FI8P) n                ! Casting of n to string.
   str = adjustl(trim(str))          ! Removing white spaces.
   if (n>=0_I8P) str='+'//trim(str)  ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   endfunction str_I8P

   elemental function str_I4P(n, no_sign) result(str)
   !< Converting integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I4P)
   !<```
   !=> -1 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I4P, no_sign=.true.)
   !<```
   !=> 1 <<<
   integer(I4P), intent(in)           :: n       !< Integer to be converted.
   logical,      intent(in), optional :: no_sign !< Flag for leaving out the sign.
   character(DI4P)                    :: str     !< Returned string containing input number plus padding zeros.

   write(str, FI4P) n                ! Casting of n to string.
   str = adjustl(trim(str))          ! Removing white spaces.
   if (n>=0_I4P) str='+'//trim(str)  ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   endfunction str_I4P

   elemental function str_I2P(n, no_sign) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I2P)
   !<```
   !=> -1 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I2P, no_sign=.true.)
   !<```
   !=> 1 <<<
   integer(I2P), intent(in)           :: n       !< Integer to be converted.
   logical,      intent(in), optional :: no_sign !< Flag for leaving out the sign.
   character(DI2P)                    :: str     !< Returned string containing input number plus padding zeros.

   write(str, FI2P) n                ! Casting of n to string.
   str = adjustl(trim(str))          ! Removing white spaces.
   if (n>=0_I2P) str='+'//trim(str)  ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   endfunction str_I2P

   elemental function str_I1P(n, no_sign) result(str)
   !< Convert integer to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I1P)
   !<```
   !=> -1 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=-1_I1P, no_sign=.true.)
   !<```
   !=> 1 <<<
   integer(I1P), intent(in)           :: n       !< Integer to be converted.
   logical,      intent(in), optional :: no_sign !< Flag for leaving out the sign.
   character(DI1P)                    :: str     !< Returned string containing input number plus padding zeros.

   write(str, FI1P) n                ! Casting of n to string.
   str = adjustl(trim(str))          ! Removing white spaces.
   if (n>=0_I1P) str='+'//trim(str)  ! Prefixing plus if n>0.
   if (present(no_sign)) str=str(2:) ! Leaving out the sign.
   endfunction str_I1P

   elemental function str_bol(n) result(str)
   !< Convert logical to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=.true.)
   !<```
   !=> T <<<
   logical, intent(in):: n   !< Logical to be converted.
   character(1)::        str !< Returned string containing input number plus padding zeros.

   write(str, '(L1)') n
   endfunction str_bol

   pure function str_a_R16P(n, no_sign, separator, delimiters, compact) result(str)
   !< Converting real array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R16P, -2._R16P])
   !<```
   !=> +0.100000000000000000000000000000000E+0001,-0.200000000000000000000000000000000E+0001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R16P, 2._R16P], no_sign=.true.)
   !<```
   !=> 0.100000000000000000000000000000000E+0001,0.200000000000000000000000000000000E+0001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R16P, -2._R16P], separator='|')
   !<```
   !=> +0.100000000000000000000000000000000E+0001|-0.200000000000000000000000000000000E+0001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R16P, -2._R16P], delimiters=['(', ')'])
   !<```
   !=> (+0.100000000000000000000000000000000E+0001,-0.200000000000000000000000000000000E+0001) <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R16P, -2._R16P], compact=.true.)
   !<```
   !=> +0.1E+1,-0.2E+1 <<<
   real(R16P),   intent(in)           :: n(:)            !< Real array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   logical,      intent(in), optional :: compact         !< Flag for *compacting* string encoding.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DR16P)                   :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   do i=1,size(n)
     strn = str_R16P(no_sign=no_sign, compact=compact, n=n(i))
     str = str//sep//trim(strn)
   enddo
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_R16P

   pure function str_a_R8P(n, no_sign, separator, delimiters, compact) result(str)
   !< Convert real array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R8P, -2._R8P])
   !<```
   !=> +0.100000000000000E+001,-0.200000000000000E+001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R8P, 2._R8P], no_sign=.true.)
   !<```
   !=> 0.100000000000000E+001,0.200000000000000E+001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R8P, -2._R8P], separator='|')
   !<```
   !=> +0.100000000000000E+001|-0.200000000000000E+001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R8P, -2._R8P], delimiters=['(', ')'])
   !<```
   !=> (+0.100000000000000E+001,-0.200000000000000E+001) <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R8P, -2._R8P], compact=.true.)
   !<```
   !=> +0.1E+1,-0.2E+1 <<<
   real(R8P),    intent(in)           :: n(:)            !< Real array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   logical,      intent(in), optional :: compact         !< Flag for *compacting* string encoding.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DR8P)                    :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   do i=1,size(n)
     strn = str_R8P(no_sign=no_sign, compact=compact, n=n(i))
     str = str//sep//trim(strn)
   enddo
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_R8P

   pure function str_a_R4P(n, no_sign, separator, delimiters, compact) result(str)
   !< Convert real array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R4P, -2._R4P])
   !<```
   !=> +0.100000E+01,-0.200000E+01 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R4P, 2._R4P], no_sign=.true.)
   !<```
   !=> 0.100000E+01,0.200000E+01 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R4P, -2._R4P], separator='|')
   !<```
   !=> +0.100000E+01|-0.200000E+01 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R4P, -2._R4P], delimiters=['(', ')'])
   !<```
   !=> (+0.100000E+01,-0.200000E+01) <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1._R4P, -2._R4P], compact=.true.)
   !<```
   !=> +0.1E+1,-0.2E+1 <<<
   real(R4P),    intent(in)           :: n(:)            !< Real array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   logical,      intent(in), optional :: compact         !< Flag for *compacting* string encoding.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DR4P)                    :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   do i=1,size(n)
     strn = str_R4P(no_sign=no_sign, compact=compact, n=n(i))
     str = str//sep//trim(strn)
   enddo
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_R4P

   pure function str_a_I8P(n, no_sign, separator, delimiters) result(str)
   !< Convert integer array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I8P, -2_I8P])
   !<```
   !=> +1,-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I8P, 2_I8P], no_sign=.true.)
   !<```
   !=> 1,2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I8P, -2_I8P], separator='|')
   !<```
   !=> +1|-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I8P, -2_I8P], delimiters=['(', ')'])
   !<```
   !=> (+1,-2) <<<
   integer(I8P), intent(in)           :: n(:)            !< Integer array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DI8P)                    :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   if (present(no_sign)) then
     do i=1,size(n)
       strn = str_I8P(no_sign=no_sign, n=n(i))
       str = str//sep//trim(strn)
     enddo
   else
     do i=1,size(n)
       strn = str_I8P(n=n(i))
       str = str//sep//trim(strn)
     enddo
   endif
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_I8P

   pure function str_a_I4P(n, no_sign, separator, delimiters) result(str)
   !< Convert integer array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I4P, -2_I4P])
   !<```
   !=> +1,-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I4P, 2_I4P], no_sign=.true.)
   !<```
   !=> 1,2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I4P, -2_I4P], separator='|')
   !<```
   !=> +1|-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I4P, -2_I4P], delimiters=['(', ')'])
   !<```
   !=> (+1,-2) <<<
   integer(I4P), intent(in)           :: n(:)            !< Integer array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DI4P)                    :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   if (present(no_sign)) then
     do i=1,size(n)
       strn = str_I4P(no_sign=no_sign, n=n(i))
       str = str//sep//trim(strn)
     enddo
   else
     do i=1,size(n)
       strn = str_I4P(n=n(i))
       str = str//sep//trim(strn)
     enddo
   endif
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_I4P

   pure function str_a_I2P(n, no_sign, separator, delimiters) result(str)
   !< Convert integer array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I2P, -2_I2P])
   !<```
   !=> +1,-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I2P, 2_I2P], no_sign=.true.)
   !<```
   !=> 1,2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I2P, -2_I2P], separator='|')
   !<```
   !=> +1|-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I2P, -2_I2P], delimiters=['(', ')'])
   !<```
   !=> (+1,-2) <<<
   integer(I2P), intent(in)           :: n(:)            !< Integer array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DI2P)                    :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   if (present(no_sign)) then
     do i=1,size(n)
       strn = str_I2P(no_sign=no_sign, n=n(i))
       str = str//sep//trim(strn)
     enddo
   else
     do i=1,size(n)
       strn = str_I2P(n=n(i))
       str = str//sep//trim(strn)
     enddo
   endif
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_I2P

   pure function str_a_I1P(n, no_sign, separator, delimiters) result(str)
   !< Convert integer array to string.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I1P, -2_I1P])
   !<```
   !=> +1,-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I1P, 2_I1P], no_sign=.true.)
   !<```
   !=> 1,2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I1P, -2_I1P], separator='|')
   !<```
   !=> +1|-2 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", str(n=[1_I1P, -2_I1P], delimiters=['(', ')'])
   !<```
   !=> (+1,-2) <<<
   integer(I1P), intent(in)           :: n(:)            !< Integer array to be converted.
   logical,      intent(in), optional :: no_sign         !< Flag for leaving out the sign.
   character(1), intent(in), optional :: separator       !< Eventual separator of array values.
   character(*), intent(in), optional :: delimiters(1:2) !< Eventual delimiters of array values.
   character(len=:), allocatable      :: str             !< Returned string containing input number.
   character(DI1P)                    :: strn            !< String containing of element of input array number.
   character(len=1)                   :: sep             !< Array values separator
   integer                            :: i               !< Counter.

   str = ''
   sep = ','
   if(present(separator)) sep = separator
   if (present(no_sign)) then
     do i=1,size(n)
       strn = str_I1P(no_sign=no_sign, n=n(i))
       str = str//sep//trim(strn)
     enddo
   else
     do i=1,size(n)
       strn = str_I1P(n=n(i))
       str = str//sep//trim(strn)
     enddo
   endif
   str = trim(str(2:))
   if (present(delimiters)) str = delimiters(1)//str//delimiters(2)
   endfunction str_a_I1P

   pure subroutine compact_real_string(string)
   !< author: Izaak Beekman
   !< date: 02/24/2015
   !<
   !< Compact a string representing a real number, so that the same value is displayed with fewer characters.
   !<
   !< @note No need to add doctest: this is tested by a lot of doctests of other TBPs.
   character(len=*),intent(inout) :: string      !< string representation of a real number.
   character(len=len(string))     :: significand !< Significand characters.
   character(len=len(string))     :: expnt       !< Exponent characters.
   character(len=2)               :: separator   !< Separator characters.
   integer(I4P)                   :: exp_start   !< Start position of exponent.
   integer(I4P)                   :: decimal_pos !< Decimal positions.
   integer(I4P)                   :: sig_trim    !< Signature trim.
   integer(I4P)                   :: exp_trim    !< Exponent trim.
   integer(I4P)                   :: i           !< counter

   string = adjustl(string)
   exp_start = scan(string, 'eEdD')
   if (exp_start == 0) exp_start = scan(string, '-+', back=.true.)
   decimal_pos = scan(string, '.')
   if (exp_start /= 0) separator = string(exp_start:exp_start)
   if ( exp_start < decimal_pos ) then ! possibly signed, exponent-less float
     significand = string
     sig_trim = len(trim(significand))
     do i = len(trim(significand)), decimal_pos+2, -1 ! look from right to left at 0s, but save one after the decimal place
       if (significand(i:i) == '0') then
         sig_trim = i-1
       else
         exit
       endif
     enddo
     string = trim(significand(1:sig_trim))
   elseif (exp_start > decimal_pos) then ! float has exponent
     significand = string(1:exp_start-1)
     sig_trim = len(trim(significand))
     do i = len(trim(significand)),decimal_pos+2,-1 ! look from right to left at 0s
       if (significand(i:i) == '0') then
         sig_trim = i-1
       else
         exit
       endif
     enddo
     expnt = adjustl(string(exp_start+1:))
     if (expnt(1:1) == '+' .or. expnt(1:1) == '-') then
       separator = trim(adjustl(separator))//expnt(1:1)
       exp_start = exp_start + 1
       expnt     = adjustl(string(exp_start+1:))
     endif
     exp_trim = 1
     do i = 1,(len(trim(expnt))-1) ! look at exponent leading zeros saving last
       if (expnt(i:i) == '0') then
         exp_trim = i+1
       else
         exit
       endif
     enddo
     string = trim(adjustl(significand(1:sig_trim)))// &
              trim(adjustl(separator))// &
              trim(adjustl(expnt(exp_trim:)))
   !else ! mal-formed real, BUT this code should be unreachable
   endif
   endsubroutine compact_real_string

   elemental function strz_I8P(n, nz_pad) result(str)
   !< Converting integer to string, prefixing with the right number of zeros.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I8P)
   !<```
   !=> 0000000000000000001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I8P, nz_pad=5)
   !<```
   !=> 00001 <<<
   integer(I8P), intent(in)           :: n      !< Integer to be converted.
   integer(I4P), intent(in), optional :: nz_pad !< Number of zeros padding.
   character(DI8P)                    :: str    !< Returned string containing input number plus padding zeros.

   write(str,FI8PZP) n                              ! Casting of n to string.
   str=str(2:)                                      ! Leaving out the sign.
   if (present(nz_pad)) str=str(DI8P-nz_pad:DI8P-1) ! Leaving out the extra zeros padding
   endfunction strz_I8P

   elemental function strz_I4P(n, nz_pad) result(str)
   !< Convert integer to string, prefixing with the right number of zeros.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I4P)
   !<```
   !=> 0000000001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I4P, nz_pad=5)
   !<```
   !=> 00001 <<<
   integer(I4P), intent(in)           :: n      !< Integer to be converted.
   integer(I4P), intent(in), optional :: nz_pad !< Number of zeros padding.
   character(DI4P)                    :: str    !< Returned string containing input number plus padding zeros.

   write(str,FI4PZP) n                              ! Casting of n to string.
   str=str(2:)                                      ! Leaving out the sign.
   if (present(nz_pad)) str=str(DI4P-nz_pad:DI4P-1) ! Leaving out the extra zeros padding
   endfunction strz_I4P

   elemental function strz_I2P(n, nz_pad) result(str)
   !< Convert integer to string, prefixing with the right number of zeros.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I2P)
   !<```
   !=> 00001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I2P, nz_pad=3)
   !<```
   !=> 001 <<<
   integer(I2P), intent(in)           :: n      !< Integer to be converted.
   integer(I4P), intent(in), optional :: nz_pad !< Number of zeros padding.
   character(DI2P)                    :: str    !< Returned string containing input number plus padding zeros.

   write(str,FI2PZP) n                              ! Casting of n to string.
   str=str(2:)                                      ! Leaving out the sign.
   if (present(nz_pad)) str=str(DI2P-nz_pad:DI2P-1) ! Leaving out the extra zeros padding
   endfunction strz_I2P

   elemental function strz_I1P(n, nz_pad) result(str)
   !< Convert integer to string, prefixing with the right number of zeros.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I1P)
   !<```
   !=> 001 <<<
   !<
   !<```fortran
   !< use penf
   !< print "(A)", strz(n=1_I1P, nz_pad=3)
   !<```
   !=> 001 <<<
   integer(I1P), intent(in)           :: n      !< Integer to be converted.
   integer(I4P), intent(in), optional :: nz_pad !< Number of zeros padding.
   character(DI1P)                    :: str    !< Returned string containing input number plus padding zeros.

   write(str,FI1PZP) n                              ! Casting of n to string.
   str=str(2:)                                      ! Leaving out the sign.
   if (present(nz_pad)) str=str(DI1P-nz_pad:DI1P-1) ! Leaving out the extra zeros padding
   endfunction strz_I1P

   function ctor_R16P(str, knd, pref, error) result(n)
   !< Convert string to real.
   !<
   !<```fortran
   !< use penf
   !< print FR16P, cton(str='-1.0', knd=1._R16P)
   !<```
   !=> -0.100000000000000000000000000000000E+0001 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   real(R16P),             intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   real(R16P)                          :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to real failed! real(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctor_R16P

   function ctor_R8P(str, knd, pref, error) result(n)
   !< Convert string to real.
   !<
   !<```fortran
   !< use penf
   !< print FR8P, cton(str='-1.0', knd=1._R8P)
   !<```
   !=> -0.100000000000000E+001 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   real(R8P),              intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   real(R8P)                           :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to real failed! real(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctor_R8P

   function ctor_R4P(str, knd, pref, error) result(n)
   !< Convert string to real.
   !<
   !<```fortran
   !< use penf
   !< print FR4P, cton(str='-1.0', knd=1._R4P)
   !<```
   !=> -0.100000E+01 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   real(R4P),              intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   real(R4P)                           :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to real failed! real(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctor_R4P

   function ctoi_I8P(str, knd, pref, error) result(n)
   !< Convert string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI8P, cton(str='-1', knd=1_I8P)
   !<```
   !=> -1 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   integer(I8P),           intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   integer(I8P)                        :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to integer failed! integer(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctoi_I8P

   function ctoi_I4P(str, knd, pref, error) result(n)
   !< Convert string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI4P, cton(str='-1', knd=1_I4P)
   !<```
   !=> -1 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   integer(I4P),           intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   integer(I4P)                        :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to integer failed! integer(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctoi_I4P

   function ctoi_I2P(str, knd, pref, error) result(n)
   !< Convert string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI2P, cton(str='-1', knd=1_I2P)
   !<```
   !=> -1 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   integer(I2P),           intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   integer(I2P)                        :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to integer failed! integer(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctoi_I2P

   function ctoi_I1P(str, knd, pref, error) result(n)
   !< Convert string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI1P, cton(str='-1', knd=1_I1P)
   !<```
   !=> -1 <<<
   character(*),           intent(in)  :: str   !< String containing input number.
   integer(I1P),           intent(in)  :: knd   !< Number kind.
   character(*), optional, intent(in)  :: pref  !< Prefixing string.
   integer(I4P), optional, intent(out) :: error !< Error trapping flag: 0 no errors, >0 error occurs.
   integer(I1P)                        :: n     !< Number returned.
   integer(I4P)                        :: err   !< Error trapping flag: 0 no errors, >0 error occurs.
   character(len=:), allocatable       :: prefd !< Prefixing string.

   read(str, *, iostat=err) n ! Casting of str to n.
   if (err/=0) then
     prefd = '' ; if (present(pref)) prefd = pref
     write(stderr, '(A,I1,A)') prefd//' Error: conversion of string "'//str//'" to integer failed! integer(', kind(knd), ')'
   endif
   if (present(error)) error = err
   endfunction ctoi_I1P

   elemental function bstr_R16P(n) result(bstr)
   !< Convert real to string of bits.
   !<
   !< @note It is assumed that R16P is represented by means of 128 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< character(128) :: b
   !< b = bstr(n=1._R16P)
   !< print "(A)", b(17:)
   !<```
   !=> 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111100111111 <<<
   real(R16P), intent(in) :: n          !< Real to be converted.
   character(128)         :: bstr       !< Returned bit-string containing input number.
   integer(I1P)           :: buffer(16) !< Transfer buffer.

   buffer = transfer(n, buffer)
   write(bstr, '(16B8.8)') buffer
   endfunction bstr_R16P

   elemental function bstr_R8P(n) result(bstr)
   !< Convert real to string of bits.
   !<
   !< @note It is assumed that R8P is represented by means of 64 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", bstr(n=1._R8P)
   !<```
   !=> 0000000000000000000000000000000000000000000000001111000000111111 <<<
   real(R8P), intent(in) :: n         !< Real to be converted.
   character(64)         :: bstr      !< Returned bit-string containing input number.
   integer(I1P)          :: buffer(8) !< Transfer buffer.

   buffer = transfer(n, buffer)
   write(bstr, '(8B8.8)') buffer
   endfunction bstr_R8P

   elemental function bstr_R4P(n) result(bstr)
   !< Convert real to string of bits.
   !<
   !< @note It is assumed that R4P is represented by means of 32 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", bstr(n=1._R4P)
   !<```
   !=> 00000000000000001000000000111111 <<<
   real(R4P), intent(in) :: n         !< Real to be converted.
   character(32)         :: bstr      !< Returned bit-string containing input number.
   integer(I1P)          :: buffer(4) !< Transfer buffer.

   buffer = transfer(n, buffer)
   write(bstr, '(4B8.8)') buffer
   endfunction bstr_R4P

   elemental function bstr_I8P(n) result(bstr)
   !< Convert integer to string of bits.
   !<
   !< @note It is assumed that I8P is represented by means of 64 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", bstr(n=1_I8P)
   !<```
   !=> 0000000000000000000000000000000000000000000000000000000000000001 <<<
   integer(I8P), intent(in) :: n    !< Real to be converted.
   character(64)            :: bstr !< Returned bit-string containing input number.

   write(bstr, '(B64.64)') n
   endfunction bstr_I8P

   elemental function bstr_I4P(n) result(bstr)
   !< Convert integer to string of bits.
   !<
   !< @note It is assumed that I4P is represented by means of 32 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", bstr(n=1_I4P)
   !<```
   !=> 00000000000000000000000000000001 <<<
   integer(I4P), intent(in) :: n    !< Real to be converted.
   character(32)            :: bstr !< Returned bit-string containing input number.

   write(bstr, '(B32.32)') n
   endfunction bstr_I4P

   elemental function bstr_I2P(n) result(bstr)
   !< Convert integer to string of bits.
   !<
   !< @note It is assumed that I2P is represented by means of 16 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", bstr(n=1_I2P)
   !<```
   !=> 0000000000000001 <<<
   integer(I2P), intent(in) :: n    !< Real to be converted.
   character(16)            :: bstr !< Returned bit-string containing input number.

   write(bstr, '(B16.16)') n
   endfunction bstr_I2P

   elemental function bstr_I1P(n) result(bstr)
   !< Convert integer to string of bits.
   !<
   !< @note It is assumed that I1P is represented by means of 8 bits, but this is not ensured in all architectures.
   !<
   !<```fortran
   !< use penf
   !< print "(A)", bstr(n=1_I1P)
   !<```
   !=> 00000001 <<<
   integer(I1P), intent(in) :: n    !< Real to be converted.
   character(8)             :: bstr !< Returned bit-string containing input number.

   write(bstr, '(B8.8)') n
   endfunction bstr_I1P

   elemental function bctor_R16P(bstr, knd) result(n)
   !< Convert bit-string to real.
   !<
   !<```fortran
   !< use penf
   !< print FR16P, bcton('00000000000000000000000000000000000000000000000000000000000000000000000000000'//&
   !<                    '000000000000000000000000000000000001111111100111111', knd=1._R16P)
   !<```
   !=> 0.100000000000000000000000000000000E+0001 <<<
   character(*), intent(in) :: bstr       !< String containing input number.
   real(R16P),   intent(in) :: knd        !< Number kind.
   real(R16P)               :: n          !< Number returned.
   integer(I1P)             :: buffer(16) !< Transfer buffer.

   read(bstr, '(16B8.8)') buffer
   n = transfer(buffer, n)
   endfunction bctor_R16P

   elemental function bctor_R8P(bstr, knd) result(n)
   !< Convert bit-string to real.
   !<
   !<```fortran
   !< use penf
   !< print FR8P, bcton('0000000000000000000000000000000000000000000000001111000000111111', knd=1._R8P)
   !<```
   !=> 0.100000000000000E+001 <<<
   character(*), intent(in) :: bstr      !< String containing input number.
   real(R8P),    intent(in) :: knd       !< Number kind.
   real(R8P)                :: n         !< Number returned.
   integer(I1P)             :: buffer(8) !< Transfer buffer.

   read(bstr, '(8B8.8)') buffer
   n = transfer(buffer, n)
   endfunction bctor_R8P

   elemental function bctor_R4P(bstr, knd) result(n)
   !< Convert bit-string to real.
   !<
   !<```fortran
   !< use penf
   !< print FR4P, bcton('00000000000000001000000000111111', knd=1._R4P)
   !<```
   !=> 0.100000E+01 <<<
   character(*), intent(in) :: bstr      !< String containing input number.
   real(R4P),    intent(in) :: knd       !< Number kind.
   real(R4P)                :: n         !< Number returned.
   integer(I1P)             :: buffer(4) !< Transfer buffer.

   read(bstr, '(4B8.8)') buffer
   n = transfer(buffer, n)
   endfunction bctor_R4P

   elemental function bctoi_I8P(bstr, knd) result(n)
   !< Convert bit-string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI8P, bcton('0000000000000000000000000000000000000000000000000000000000000001', knd=1_I8P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: bstr !< String containing input number.
   integer(I8P), intent(in) :: knd  !< Number kind.
   integer(I8P)             :: n    !< Number returned.

   read(bstr,'(B'//trim(str(bit_size(knd), .true.))//'.'//trim(str(bit_size(knd), .true.))//')') n
   endfunction bctoi_I8P

   elemental function bctoi_I4P(bstr, knd) result(n)
   !< Convert bit-string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI4P, bcton('00000000000000000000000000000001', knd=1_I4P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: bstr !< String containing input number.
   integer(I4P), intent(in) :: knd  !< Number kind.
   integer(I4P)             :: n    !< Number returned.

   read(bstr,'(B'//trim(str(bit_size(knd), .true.))//'.'//trim(str(bit_size(knd), .true.))//')') n
   endfunction bctoi_I4P

   elemental function bctoi_I2P(bstr, knd) result(n)
   !< Convert bit-string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI2P, bcton('0000000000000001', knd=1_I2P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: bstr !< String containing input number.
   integer(I2P), intent(in) :: knd  !< Number kind.
   integer(I2P)             :: n    !< Number returned.

   read(bstr,'(B'//trim(str(bit_size(knd), .true.))//'.'//trim(str(bit_size(knd), .true.))//')') n
   endfunction bctoi_I2P

   elemental function bctoi_I1P(bstr, knd) result(n)
   !< Convert bit-string to integer.
   !<
   !<```fortran
   !< use penf
   !< print FI1P, bcton('00000001', knd=1_I1P)
   !<```
   !=> 1 <<<
   character(*), intent(in) :: bstr !< String containing input number.
   integer(I1P), intent(in) :: knd  !< Number kind.
   integer(I1P)             :: n    !< Number returned.

   read(bstr,'(B'//trim(str(bit_size(knd), .true.))//'.'//trim(str(bit_size(knd), .true.))//')') n
   endfunction bctoi_I1P
endmodule penf_stringify
